#!/usr/bin/python -S
import sitecustomize # Sets defaultencoding and imports site
import datetime
import os
import sys
import time
import Pyro.core

#assert sys.getdefaultencoding() == "utf-8", "You should run this with python -S to override encoding"
from django.core.management import setup_environ

try:
    import settings
except ImportError:
    sys.stderr.write("""Error: Can't find the file 'settings.py' in the
        directory containing %r. It appears you've customized things.\nYou'll
        have to run django-admin.py, passing it your settings module.\n(If the
        file settings.py does indeed exist, it's causing an ImportError somehow
        .)\n""" % __file__)
    sys.exit(1)

project_directory = setup_environ(settings)
project_name = os.path.basename(project_directory)
os.environ['DJANGO_SETTINGS_MODULE'] = "%s.settings" % project_name

import django.db as db
from django.db.models import Q
from django.conf import settings

from instafeed.subscriptions.models import FeedSubscription
from instafeed.subscriptions.models import CloudServer, ServerSubscriber
from instafeed.tasks import delay_task, retryMessage

def sendNewEntries(feedId, **kargs):
    feed = FeedSubscription.objects.get(id=feedId)
    log = "Message received 'sendNewEntries' for subscription (%s) id(%s), user(%s)\n" % (feed.name, feed.id,
        feed.user.username)
    errors = []
    new_entries = False
    for newEntry, ok, errors in feed.sendNewEntries():
        new_entries = True
        log += "NewEntry (%s) link(%s) - Conduits OK: %d, errors: %d\n" % (newEntry.title, newEntry.link,
            ok, len(errors))
        if errors:
            log += "<ul>\n"
        for conduit, error in errors:
            log += "<li>Error sending through conduit (%s) id(%s): \n<pre>%s</pre>\n</li>" % (conduit.name,
                conduit.id, error)
        if errors:
            log += "</ul>\n"
        log += "\n"
    if not new_entries:
        log += "Couldn't find any new entries, nothing sent. Last entry id(%s)" % feed.last_entry_id
    print "*" * 70
    print log
    print "*" * 70
    if settings.WP_LOG:
        settings.WP_LOG.publishPost(log.split("\n", 1)[0], log,
            categories=["sendNewEntries", "instafeed", feed.user.username] + (errors and ["error"] or []))

def notifySubscribers(cloudserverId, **kwargs):
    """checks the feed for new entries and notify subscribers if any.
       removes expired subscribers first
    """
    cloudserver = CloudServer.objects.get(id=cloudserverId)
    log = "Message received 'notifySubscribers' for cloud server %s (%s), user: %s\n" % (cloudserver.name,
        cloudserver.id, cloudserver.user.username)
    #Removes all expired and failing subscribers
    now = datetime.datetime.now()
    max_retries = settings.MAX_RETRIES
    to_remove = ServerSubscriber.objects.filter(Q(server=cloudserver),
                                    Q(expiration_date__lt=now) | Q(fail_count__gt=max_retries))
    to_remove.delete()
    #Notify subscribers
    errors = []
    if len(cloudserver.serversubscriber_set.all()) > 0:
        ok, errors = cloudserver.notifySubscribers()
        if not ok and not errors:
            log += "Couldn't find any new entries for (%s) at (%s)" % (cloudserver.name, cloudserver.url)
        else:
            log += "New entries detected - Subscribers notified: %d, errors: %d\n" % (ok, len(errors))
            log += "Updating cloudfeed"
        if errors:
            log += "<ul>\n"
            for subscriber, error in errors:
                log += "<li>Error notifying subscriber (%s): \n<pre>%s</pre>\n</li>" % (subscriber.id, error)
            log += "</ul>\n"
    else:
        log += "Couldn't find any subscriber for server (%s)" % cloudserver.name
    print "-" * 70
    print log
    print "-" * 70
    if settings.WP_LOG:
        settings.WP_LOG.publishPost(log.split("\n", 1)[0], log,
            categories=["notifySubscribers", "instafeed", cloudserver.user.username] +
                        (errors and ["error"] or []))

def queueServer_listener(serverURL, loginInfo):
    "listen for tasks and proecess them"
    handlers = {
        'sendNewEntries': sendNewEntries,
        'notifySubscribers': notifySubscribers,
    }

    print 'Connecting to server at %s' % serverURL
    server = Pyro.core.getProxyForURI(serverURL)
    print 'Listening for messages'
    while True:
        msg = server.pop(loginInfo)
        if msg is None:
            time.sleep(1.0)
            continue
        print '\nNew message found, looking for task'
        try:
            task = msg['task']
        except KeyError:
            print >>sys.stderr, "Task not found on msg (%s)" % msg
            continue
        print 'Found task %s' % task
        if task not in handlers:
            print >>sys.stderr, "Ignoring unknown task (%s)" % task
            continue
        params = {}
        # Hack needed for python < 2.6 because unicode strings
        # cannot be passed as kwargs.
        for k, v in msg.iteritems():
            params[str(k)] = str(v)

        try:
            handlers[task](**params)
            db.connection.connection.commit()
        except Exception, e:
            from sys import exc_info
            from traceback import format_tb

            e_type, e_value, tb = exc_info()
            traceback = ['Traceback (most recent call last):']
            traceback += format_tb(tb)
            traceback.append('%s: %s' % (e_type.__name__, e_value))
            print '\n'.join(traceback)
            try:
                db.connection.connection.rollback()
            except:
                pass
            retryMessage(msg)

if __name__ == "__main__":
    queueServer_listener(settings.QUEUESERVER_URL, settings.QUEUESERVER_LOGIN)
